#ifndef OpenCLTemplate_H_
#define OpenCLTemplate_H_

#define PRECISION double

#include <Timer.h>
#include <string>
#include <CL/cl.h>

class COpenCLTemplate
{
private:
	// Size of problem domain
	const unsigned int nInputWidth/*Width*/;
	const unsigned int nWidth;
	const unsigned int nHeight;			//self added
	const unsigned int nFilterWidth;
	//const unsigned int nWidth; //In OpenCLTemplate.cpp we will  assume that the size of both the matrices is exactly the same , hence will be represented by Width
	unsigned int Width;// this will be the result of the multiplication of the rows*cols and rows2*cols2 AND IMPORTANTLY IT IS NOT CONST UNSIGNED INT
	//unsigned int Width2;
	//unsigned int Width3;
	//unsigned int l;//l=rows2
	unsigned int cpu;
	unsigned int gpu;
	int start_cpu;
	int end_cpu;
	int start_gpu;
	int end_gpu;
	// Host data arrays.
	PRECISION* /*input*/Input;
	PRECISION* Filter;
	PRECISION* Output;
	// Device data arrays.
	cl_mem d_Input;
	cl_mem d_Filter;
	cl_mem d_Output; //Don't need to add an output's arguments to COpenCLTemplate Function

	// ============ OPENCL related parameters ===========
	// OPENCL context/device/program
	cl_context context;
	cl_device_id *devices;
	cl_command_queue commandQueue;
	cl_program program;
	cl_kernel kernel;
	// ==================================================

	// Timer variables.
	__int64 tStart;
	__int64 tEnd;
	__int64 tDelta;
	bool tPaused;

public://For the time we ignore const PRECISION (multiplier)

	COpenCLTemplate(unsigned int=128U, unsigned int=128U, unsigned int=128U, unsigned int=128U, unsigned int=16384U, unsigned int=5U, unsigned int=5U, int=0U,  int=0U,  int=0U, int=0U/*INSERT PLATFORM*const PRECISION=2.0*/);//Default values only. They are actually set according to user request

	// Memory allocation and initialisation.
	int AllocateMemoryCPU();
	int InitialiseCPU();
	int InitialiseCL();			// Search and allocate a device.
	int AllocateMemoryGPU();
	int InitialiseCLKernelsGPU(); // Build/attach kernels to respective kernel functions and set arguments.
	int RunCLKernels();

	// Complete run encapsulating all the sub-functions.
	int CompleteRun();

	// Timing.
	void StartTimer();
	void StopTimer();
	void ResetTimer();
	double GetElapsedTime();

	std::string convertToString(const char * filename);

	int SafeCall(cl_int, const char []=NULL);

	int CleanupCPU();
	int CleanupCL();
	int CleanupGPU();
	~COpenCLTemplate ();
};
#endif // #ifndef OpenCLTemplate_H_
